﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media;
using Galaktika.BI.Charting;
using Galaktika.BI.Addin.VisifireChart.Runtime.PivotChart;
using Galaktika.BI.Extensibility.Dom;
using Galaktika.BI.Runtime.Services;
using Visifire.Charts;
using Ranet.Olap.Core.Data;
using Ranet.AgOlap.Controls.ContextMenu;
using Galaktika.BI.Silverlight.Runtime.Data;
using Galaktika.BI.Silverlight.Runtime.Data.Olap;
using Galaktika.BI.Extensibility.ComponentModel;
using Galaktika.BI.Extensibility;

namespace Galaktika.BI.Addin.VisifireChart.Runtime
{
    public class ChartingCommon
    {
        public const string DEFAULT_PALETTE_NAME = "Visifire1";
        private Chart m_chart;
        //private RanetChart_v2 m_chart2;

        public ChartingCommon(Chart chart)
        {
            m_chart = chart;
        }


        public void UpdateChartPalettes(string paletteName, IBindingContext context)
        {
            if (this.m_chart.EmbeddedColorSets != null && this.m_chart.EmbeddedColorSets.GetColorSetByName(paletteName) != null)
            {
                this.m_chart.ColorSet = paletteName; //initialize with APaletteName
            }
            else
            {
                if (paletteName.Contains("."))
                {
                    var userPalette = new ColorSet();
                    userPalette.Id = paletteName;
                    userPalette.Brushes = this.UpdateChartPalettesFromGlobalSource(context, paletteName);
                    this.m_chart.ColorSets.Add(userPalette);
                    this.m_chart.ColorSet = userPalette.Id;
                }
                else
                    this.m_chart.ColorSet = ChartingCommon.DEFAULT_PALETTE_NAME;
            }
        }

        private Collection<Brush> UpdateChartPalettesFromGlobalSource(IBindingContext context, string paletteName)
        {

            var app = context.Services.GetService(typeof(IAppManager)) as IAppManager;
            BrickPalette globalPalette = PaletteHelper.GetPalette(paletteName, app);
            if (globalPalette != null)
                return this.AddGlobalPaletteToChartRepository(globalPalette);
            return null;
        }

        private Collection<Brush> AddGlobalPaletteToChartRepository(BrickPalette userPaletteEntry)
        {
            string paletteName = userPaletteEntry.Name;
            var brushes = new Collection<Brush>();
            foreach (var userPaletteItem in userPaletteEntry.Items)
            {
                if (userPaletteItem.Color2 != null)
                {
                    var coll = new GradientStopCollection();
                    coll.Add(new GradientStop()
                    {
                        Color = userPaletteItem.Color1
                    });
                    coll.Add(new GradientStop()
                    {
                        Color = userPaletteItem.Color2,
                        Offset = 2
                    });
                    var paletteEntry = new LinearGradientBrush(coll, 45);
                    brushes.Add(paletteEntry);
                }
                else
                {
                    brushes.Add(new SolidColorBrush(userPaletteItem.Color1));
                }
            }
            return brushes;
        }

        public DataSeries[] CreateBubbleSeries(object aDataSource, string format)
        {
            var seriesList = new List<DataSeries> { };

            if (aDataSource is DataTableWrapper)
            {

                try
                {
                    var data = DataTable.Create(aDataSource as DataTableWrapper);
                    //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                    var dataCollection = new DataPointCollection();
                    int j = 0;
                    for (j = 0; j < data.Rows.Count; j++)
                    {
                        for (int i = 0; i < data.Columns.Count; i += 2)
                        {

                            var xObject = data.Rows[j][i];
                            var yObject = data.Rows[j][i + 1];

                            dataCollection.Add(new DataPoint() { YValue = Convert.ToDouble(yObject.Value), AxisXLabel = xObject.Value.ToString() });
                        }
                    }

                    var s = new DataSeries();
                    foreach (var d in dataCollection)
                        s.DataPoints.Add(d);
                    seriesList.Add(s);
                }
                catch (InvalidCastException e)
                {
                    throw new InformationalException(Localization.Exc_InvalidDataBinding,e);
                }
                
            }
            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;
                int j = 0;

                var series = new DataSeries();
                var dataSource = new FlatDescriptionCollection();
                foreach (var rows in data.Axes[1].Positions)
                {
                    if (data.GetCellDescription(i, j).Value != null)
                    {
                        try
                        {
                            if (data.GetCellDescription(i, j).Value.Value == null)
                            {
                                j++;
                                continue;
                            }
                            string m_YValueFormat;

                            var obj = new FlatDescription();
                            var point = new DataPoint();
                            point.Parent = series;

                            double value;
                            if (ValueHelper.TryConvert(data.GetCellDescription(i, j).Value.Value, out value))
                                point.XValue = value;
                            else
                                point.AxisXLabel = data.GetCellDescription(i, j).Value.Value.ToString();

                            if (!string.IsNullOrEmpty(format))
                            {
                                point.LabelText = format;
                            }
                            //GetFormattedValue(format, out m_YValueFormat);
                            //point.Parent.YValueFormatString = m_YValueFormat;
                            //point.LabelText = value.ToString("### ##0.##");
                            obj.DisplayValue = value;
                            point.YValue = ValueHelper.ToDouble(data.GetCellDescription(i + 1, j).Value.Value);
                            obj.ArgumentSegments.Add(point.YValue);
                            point.ZValue = ValueHelper.ToDouble(data.GetCellDescription(i + 2, j).Value.Value);
                            obj.ZValue = point.ZValue;
                            if (!String.IsNullOrEmpty(point.AxisXLabel))
                                point.Name = point.AxisXLabel + i.ToString();
                            var seriesMembers = from y in rows.Members
                                                select data.Axes[1].Members[y.Id].Caption;
                            point.LegendText = string.Join(".", seriesMembers.ToArray());
                            point.ToolTipText = String.Format("{0}\\n#XValue\\n#YValue\\n#ZValue", point.LegendText);
                            //point.ShowInLegend = true;


                            series.DataPoints.Add(point);
                            foreach (var members in rows.Members)
                            {
                                obj.UniqueNameSegments.Add(data.Axes[1].Members[members.Id].Caption);
                            }
                            dataSource.Add(obj);
                            j++;
                        }
                        catch
                        {
                            continue;
                        }
                    }
                }                
                series.Tag = dataSource;
                //series.LabelEnabled = true;
                //series.SelectionEnabled = true;
                seriesList.Add(series);               
            }
            return seriesList.ToArray();
        }


        public List<DataSeries> ProcessPivotTable(object aDataSource, object diagramType,string format, bool legendVisible)
        {

            //object chartSeries = null;
            var seriesList = new List<DataSeries> { };
            bool isDateTime = false;

            if (aDataSource is DataTableWrapper)
            {

                try
                {
                    var data = DataTable.Create(aDataSource as DataTableWrapper);
                    //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                    var dataCollection = new DataPointCollection();
                    int j = 0;
                    for (j = 0; j < data.Rows.Count; j++)
                    {
                        for (int i = 0; i < data.Columns.Count; i+=2)
                        {

                            var xObject = data.Rows[j][i];
                            var yObject = data.Rows[j][i + 1];

                            dataCollection.Add(new DataPoint() {YValue = Convert.ToDouble(yObject.Value), AxisXLabel = xObject.Value.ToString()});                                                        
                        }
                    }

                    var s = new DataSeries();
                    foreach (var d in dataCollection)
                        s.DataPoints.Add(d);
                    seriesList.Add(s);
                }
                catch (InvalidCastException e)
                {
                    throw new InformationalException(Localization.Exc_InvalidDataBinding,e);
                }
                
            }

            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;
                foreach (var rows in data.Axes[0].Positions)
                {
                    int j = 0;
                    var series = new DataSeries();
                    var dataSource = new FlatDescriptionCollection();
                    string m_YFormatValue = string.Empty;

                    foreach (var columns in data.Axes[1].Positions)
                    {
                        var obj = new FlatDescription();
                        var point = new DataPoint();
                        point.Parent = series;
                        foreach (var members in columns.Members)
                        {
                            if (!String.IsNullOrEmpty(data.Axes[1].Members[members.Id].Caption))
                            {
                                DateTime arg;
                                obj.ArgumentSegments.Add(data.Axes[1].Members[members.Id].Caption);
                                point.AxisXLabel = data.Axes[1].Members[members.Id].Caption;
                                //point.ShowInLegend = false;
                                try
                                {
                                    DateTime date;
                                    obj.UniqueNameSegments.Add(data.Axes[1].Members[members.Id].UniqueName);
                                    if (data.GetCellDescription(i, j).Value != null)
                                    {
                                        if (ValueHelper.TryConvert(
                                            data.GetCellDescription(i, j).Value.Value, out date))
                                        {
                                            obj.DisplayValue = date.ToShortDateString();
                                        }
                                        else
                                        {
                                            double value =
                                                Convert.ToDouble(data.GetCellDescription(i, j).Value.Value);
                                            point.YValue = value;
                                            obj.DisplayValue = value;
                                            //string format = GetFormattedValue(formatString,
                                            //                                        out m_YFormatValue);
                                            if (!string.IsNullOrEmpty(format))
                                            {
                                                point.LabelText = format;
                                                //point.Parent.YValueFormatString = m_YFormatValue;
                                            }
                                            point.ShowInLegend = false;
                                            if (diagramType is ViewTypeCharting)
                                                if (((ViewTypeCharting)diagramType) == ViewTypeCharting.Pie ||
                                                ((ViewTypeCharting)diagramType) == ViewTypeCharting.Doughnut)
                                            {
                                                if (data.GetCellDescription(i, j).Value.Value == null)
                                                {
                                                    continue;
                                                }
                                                point.ShowInLegend = true;
                                                //point.LabelText = value.ToString("### ### ### ##0.##");
                                            }
                                            if (value == 0)
                                                point.LabelEnabled = false;
                                        }
                                    }
                                }
                                catch
                                {
                                    continue;
                                }
                            }
                        }
                        point.Name = point.AxisXLabel + i.ToString();
                        series.DataPoints.Add(point);
                        dataSource.Add(obj);
                        j++;
                    }
                    i++;

                    series.Tag = dataSource;
                    var rowMembers = data.Axes[0].Members;
                    var seriesMembers = from y in rows.Members
                                        select rowMembers[y.Id].Caption;
                    string tip1 = string.Join(".", seriesMembers.ToArray());
                    series.Name = tip1;
                    series.ToolTipText = String.Format("{0}\\n#AxisXLabel\\n#YValue", tip1);
                
                    if (diagramType is ViewTypeCharting)
                        if ((ViewTypeCharting)diagramType != ViewTypeCharting.Pie && (ViewTypeCharting)diagramType != ViewTypeCharting.Doughnut)
                        series.LegendText = string.Join(".", seriesMembers.ToArray());
                    //else
                    //{
                    //    series.LabelText = "#YValue";//string.Join(".", seriesMembers.ToArray());                       
                    //    series.YValueFormatString = "### ### ### ##0.##";                        
                    //}
                    seriesList.Add(series);
                }

            }                       
           return seriesList;
           //В случае использования Зум-скроллов производим их настройку           
        }

        public DataSeries[] GetSeriesFromDataSourceFlat(object aDataSource, object diagramType, string format, string toolTipFormatString, ChartSeries chartSeries)
        {
            var seriesList = new List<DataSeries> { };

            if (aDataSource is DataTableWrapper)
            {
                try
                {
                    var data = DataTable.Create(aDataSource as DataTableWrapper);
                    //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                    var dataCollection = new DataPointCollection();
                    int j = 0;
                    for (j = 0; j < data.Rows.Count; j++)
                    {
                        for (int i = 0; i < data.Columns.Count; i += 2)
                        {

                            var xObject = data.Rows[j][i];
                            var yObject = data.Rows[j][i + 1];

                            dataCollection.Add(new DataPoint() { YValue = Convert.ToDouble(yObject.Value), AxisXLabel = xObject.Value.ToString() });
                        }
                    }

                    var s = new DataSeries();
                    foreach (var d in dataCollection)
                        s.DataPoints.Add(d);
                    seriesList.Add(s);
                }
                catch (InvalidCastException e)
                {
                    throw new InformationalException(Localization.Exc_InvalidDataBinding,e);
                }                

            }
            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;
                foreach (var rows in data.Axes[0].Positions)
                {
                    int j = 0;
                    var dataSource = new FlatDescriptionCollection();
                    var series = new DataSeries();
                    double counter = 0;
                    string m_YFormatValue = string.Empty;
                    foreach (var columns in data.Axes[1].Positions)
                    {
                        var obj = new FlatDescription();
                        var point = new DataPoint();
                        point.Parent = series;
                        foreach (var members in columns.Members)
                        {
                            if (!String.IsNullOrEmpty(data.Axes[1].Members[members.Id].Caption))
                            {
                                obj.ArgumentSegments.Add(data.Axes[1].Members[members.Id].Caption);
                                point.AxisXLabel = data.Axes[1].Members[members.Id].Caption;
                                //counter += 20;
                                //point.XValue = counter;
                                try
                                {
                                    DateTime date;
                                    obj.UniqueNameSegments.Add(data.Axes[1].Members[members.Id].UniqueName);
                                    if (data.GetCellDescription(i, j).Value != null)
                                    {
                                        if (ValueHelper.TryConvert(
                                            data.GetCellDescription(i, j).Value.Value, out date))
                                        {
                                            obj.DisplayValue = date.ToShortDateString();
                                        }
                                        else
                                        {
                                            if (data.GetCellDescription(i, j).Value.Value == null)
                                            {
                                                obj.DisplayValue = 0;
                                                continue;
                                            }

                                            double value =
                                                Convert.ToDouble(data.GetCellDescription(i, j).Value.Value);
                                            point.YValue = value;
                                            //string format = GetFormattedValue(formatString,
                                            //                                    out m_YFormatValue);
                                            point.ShowInLegend = false;
                                            if (!string.IsNullOrEmpty(format))
                                            {
                                                point.LabelText = format;
                                                //point.Parent.YValueFormatString = m_YFormatValue;
                                            }
                                            if (diagramType is ViewTypeCharting)
                                                if (((ViewTypeCharting) diagramType) == ViewTypeCharting.Pie ||
                                                    ((ViewTypeCharting) diagramType) == ViewTypeCharting.Doughnut)
                                                {
                                                    if (data.GetCellDescription(i, j).Value.Value == null)
                                                    {
                                                        continue;
                                                    }
                                                    point.ShowInLegend = true;
                                                    //point.LabelText = value.ToString("### ### ### ##0.##");
                                                }
                                            if (value == 0)
                                                point.LabelEnabled = false;
                                            obj.DisplayValue = value;
                                        }
                                    }
                                }
                                catch
                                {
                                    continue;
                                }
                            }
                        }
                        point.Name = point.AxisXLabel + i.ToString();
                        series.DataPoints.Add(point);
                        dataSource.Add(obj);
                        j++;
                    }
                    i++;

                    series.Tag = dataSource;
                    var seriesMembers = from y in rows.Members
                                        select data.Axes[0].Members[y.Id].Caption;
                    string tip1 = string.Join(".", seriesMembers.ToArray());
                    series.Name = tip1;
                    if (string.IsNullOrEmpty(toolTipFormatString))
                        series.ToolTipText = String.Format("{0}\\n#AxisXLabel\\n#YValue", tip1);
                    if (diagramType is ViewTypeCharting)
                        if ((ViewTypeCharting) diagramType != ViewTypeCharting.Pie &&
                            (ViewTypeCharting) diagramType != ViewTypeCharting.Doughnut)
                            series.LegendText = string.Join(".", seriesMembers.ToArray());
                    //series.LabelText = "#YValue";//string.Join(".", seriesMembers.ToArray());                       
                    //if (string.IsNullOrEmpty(formatString))
                    //    series.YValueFormatString = "### ### ### ##0.##";
                    //else
                    //    series.YValueFormatString = formatString;
                    //if ((chartSeries != null)&& (chartSeries.APointsValueFormat == NumericFormat.Currency))
                    //{
                    //    //series.LabelText = "#YValue $";
                    //    series.YValueFormatString = "### ### ##0.##$";
                    //}
                    //else if ((chartSeries !=null)&& (chartSeries.APointsValueFormat == NumericFormat.Percent))
                    //{
                    //    series.LabelText = "#YValue%";
                    //    series.YValueFormatString = "### ### ##0.##";
                    //}
                    seriesList.Add(series);
                }

            }
            return seriesList.ToArray();
        }


        private string GetFormattedValue(string formatString, out string m_YValueFormat)
        {
            string resultValue = string.Empty;
            m_YValueFormat = string.Empty;

            string service = string.Empty;
            bool isService = false;
            if (!String.IsNullOrEmpty(formatString))
            {
                foreach (var str in formatString.ToCharArray())
                {
                    if (str == '{')
                    {
                        isService = true;
                        service = string.Empty;
                    }
                    else if (str == '}')
                    {
                        isService = false;
                        if (service.ToLower().Contains("value"))
                            service = service.Replace("value", "#YValue");
                        if (service.ToLower().Contains("label"))
                            service = service.Replace("label", "#AxisXLabel");
                        if (service.ToLower().Contains("percent"))
                            service = service.Replace("percent", "#Percentage");
                        var strings = service.Split(new string[] {"|"}, StringSplitOptions.None);
                        if (strings.Count() > 1 && strings[1].Contains(","))
                            m_YValueFormat = "###,###,###,##0";
                        else
                            m_YValueFormat = "### ### ### ##0";

                        double index = 0;
                        if (strings.Count() > 1 && ValueHelper.TryConvert(strings[1][0].ToString(), out index))
                        {
                            if (index > 0)
                            {
                                m_YValueFormat += ".";
                                while (index > 0)
                                {
                                    index--;
                                    m_YValueFormat += "#";
                                }
                            }
                        }

                        resultValue += strings[0];
                        service = string.Empty;
                    }
                    else
                    {
                        service += str;
                        if (!isService)
                            resultValue += str;
                    }

                }
            }
            return resultValue;
        }

        public void ParseArgsOnMenuItems(CustomContextMenu menu)
        {
            var dp = menu.Tag as DataPoint;
            if (dp != null)
            {
                var parsableArgs = new Dictionary<string, string>();
                foreach (var arg in this.GetContextArgs(dp, dp.Parent))
                {
                    parsableArgs.Add("{{" + arg.Key + "}}", arg.Value);
                }

                foreach (var element in menu.Items)
                {
                    var item = element as ContextMenuItem;
                    if (item == null) continue;
                    var info = item.Tag as ActionInfo;
                    if (info == null) continue;

                    string caption = info.ACaption;
                    foreach (var pArg in parsableArgs)
                    {
                        if (caption.Contains(pArg.Key))
                        {
                            caption = caption.Replace(pArg.Key, pArg.Value);
                        }
                    }
                    item.Caption = caption;
                }
            }
        }
        
        public IDictionary<string, string> GetContextArgs(DataPoint mi, DataSeries series)
        {
            var args = new Dictionary<string, string>();
            if (mi != null)
            {
                if ((mi.Parent.Tag as FlatDescriptionCollection) != null)
                {
                    var dataSource = mi.Parent.Tag as FlatDescriptionCollection;
                    //тут найти новмер значения mi.PointIndex
                    for (int i = 0; i < dataSource[series.DataPoints.IndexOf(mi)].ArgumentSegments.Count; i++)
                    {
                        args.Add(String.Format("UNIQUE_NAME{0}", i), dataSource[series.DataPoints.IndexOf(mi)].UniqueNameSegments.ToArray()[i]);
                        args.Add(String.Format("CAPTION{0}", i), dataSource[series.DataPoints.IndexOf(mi)].ArgumentSegments[i].ToString());
                    }
                    args.Add("seriesName", series.Name); // имя серии на которой был произведен клик
                    args.Add("label", dataSource[series.DataPoints.IndexOf(mi)].Argument.ToString()); // подпись по оси X (аргумент)
                    args.Add("value", dataSource[series.DataPoints.IndexOf(mi)].DisplayValue.ToString()); // значение

                }
            }

            return args;
        }

    }
}
